{"componentChunkName":"component---src-templates-post-js","path":"/simply-learn-full-stack-6","result":{"data":{"site":{"siteMetadata":{"title":"neohed","description":"Blog posts on web development and related areas","author":{"name":"neohed"},"keywords":["Web Development","JavaScript"]}},"mdx":{"frontmatter":{"title":"simply learn-full-stack-6","description":"Full-Stack React & Node.js - HTTP POST","date":"November 21, 2022","author":null,"banner":null,"slug":"simply-learn-full-stack-6","keywords":null},"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"slug\": \"simply-learn-full-stack-6\",\n  \"date\": \"2022-11-21T11:19:35\",\n  \"title\": \"simply learn-full-stack-6\",\n  \"description\": \"Full-Stack React & Node.js - HTTP POST\",\n  \"published\": true\n};\n\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\n\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"h1\", null, \"Simply Learn Full-Stack React & Node.js\"), mdx(\"p\", null, \"Now we're going to \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"POST\"), \" data to our server from the client.\"), mdx(\"p\", null, \"Previously we've used HTTP GET requests which are for getting data.  To add data we use HTTP POST.\"), mdx(\"p\", null, \"First we need to make a few small changes to our \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"node-server\"), \".\"), mdx(\"p\", null, \"Edit \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"note.controller.js\"), \" to:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-javascript\"\n  }), \"const note = {\\n  id: 1,\\n  title: 'A Note',\\n  content: 'Lorem ipsum dolor sit amet',\\n  author: 'neohed',\\n  lang: 'en',\\n  isLive: true,\\n  category: '',\\n}\\n\\nasync function getNote(req, res) {\\n  res.json({ note });\\n}\\n\\nasync function postNote(req, res) {\\n  const {body} = req;\\n  const {id, title, content, author, lang, isLive, category} = body;\\n\\n  console.log('Server received data:');\\n  console.log({id, title, content, author, lang, isLive, category})\\n\\n  res\\n    .status(200)\\n    .json({\\n      message: 'Ok'\\n    })\\n}\\n\\nmodule.exports = {\\n  getNote,\\n  postNote\\n}\\n\")), mdx(\"p\", null, \"We've added a new function, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"postNote\"), \". As we don't yet have a DB we simply log out the data to prove we've received it.\"), mdx(\"p\", null, \"Next, edit \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"routes/index.js\"), \" to:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-javascript\"\n  }), \"const express = require('express');\\nconst noteRouter = express.Router();\\nconst noteController = require('../controllers/note.controller');\\n\\nnoteRouter.get('', noteController.getNote);\\nnoteRouter.post('', noteController.postNote);\\n\\nconst routes = app => {\\n  app.use('/note', noteRouter);\\n};\\n\\nmodule.exports = routes\\n\")), mdx(\"p\", null, \"Notice that we mounted our new controller method \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"noteController.postNote\"), \" to the same endpoint as \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"getNote\"), \". Both are accessed from the same URL \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/note\")), mdx(\"p\", null, \"This is RESTful architecture.  It stands for REpresentational State Transfer.  The key point is that the URL endpoint, or segment, we use represents the entity, and the HTTP verb, e.g., GET or POST, represents the action!  The object entity is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"note\"), \" so the URL endpoint is also \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"note\"), \" for all operations. To distinguish between different operations such as \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"GET\"), \", \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"POST\"), \" and later \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"DELETE\"), \", and others, we use the HTTP verbs which we send in our fetch request.\"), mdx(\"p\", null, \"We use specific express router functions \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".get()\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".post()\"), \" and later \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".delete()\"), \", so that express knows, that when an HTTP \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"GET\"), \" request for the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/note\"), \" URL endpoint is received, it should be routed to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".getNote\"), \" and when an HTTP \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"POST\"), \" is received it should be routed to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".postNote()\")), mdx(\"p\", null, \"Following a RESTful architecture means your server API will be simple and clean. Using the combination of URL segments and HTTP verbs to architect the conversation between client and server allows for a simple and expressive representation.\"), mdx(\"p\", null, \"Next we need to update our \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"react-client\")), mdx(\"p\", null, \"First a little bit of refactoring. Create a new file in \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"react-client\"), \" called \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"strings.js\"), \" and paste in this code:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-javascript\"\n  }), \"const isNullOrUndefined = prop => prop === null\\n  || prop === undefined;\\nconst isEmptyString = prop => isNullOrUndefined(prop)\\n  || prop === '';\\nconst capitalize = word =>\\n  word.charAt(0).toUpperCase() +\\n  word.slice(1).toLowerCase();\\n\\nfunction titleFromName(name) {\\n  if (isEmptyString(name)) {\\n    return '';\\n  }\\n\\n  return name.split(/(?=[A-Z])|\\\\s/).map(s => capitalize(s)).join(' ')\\n}\\n\\nexport {\\n  isNullOrUndefined,\\n  isEmptyString,\\n  capitalize,\\n  titleFromName,\\n}\\n\")), mdx(\"p\", null, \"Next, edit \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Form.js\"), \" to:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"import React from 'react';\\nimport InputLabel from \\\"./InputLabel\\\";\\nimport {isEmptyString, titleFromName} from \\\"./strings\\\";\\nimport './form.css'\\n\\nconst Form = ({entity, onSubmitHandler}) => {\\n  return (\\n    <form onSubmit={e => {\\n      const form = e.target;\\n      const newEntity = Object.values(form).reduce((obj, field) => {\\n        if (!isEmptyString(field.name)) {\\n          obj[field.name] = field.value\\n        }\\n\\n        return obj\\n      }, {})\\n\\n      onSubmitHandler(newEntity);\\n\\n      e.stopPropagation();\\n      e.preventDefault()\\n    }}>\\n      {\\n        Object.entries(entity).map(([entityKey, entityValue]) => {\\n          if (entityKey === \\\"id\\\") {\\n            return <input\\n              type=\\\"hidden\\\"\\n              name=\\\"id\\\"\\n              key=\\\"id\\\"\\n              value={entityValue}\\n            />\\n          } else {\\n            return <InputLabel\\n              id={entityKey}\\n              key={entityKey}\\n              label={titleFromName(entityKey)}\\n              type={\\n                typeof entityValue === \\\"boolean\\\"\\n                  ? \\\"checkbox\\\"\\n                  : \\\"text\\\"\\n              }\\n              value={entityValue}\\n            />\\n          }\\n        })\\n      }\\n      <button\\n        type=\\\"submit\\\"\\n      >\\n        Submit\\n      </button>\\n    </form>\\n  );\\n};\\n\\nexport default Form;\\n\")), mdx(\"p\", null, \"The main change, other than removing the string utility functions, is to add a form onSubmit event handler that grabs all form fields and adds the name & value pairs as properties and values in an object, then passes that object to an event handler parameter.\"), mdx(\"p\", null, \"Next edit \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"AddEditNote.js\"), \" to implement this new \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"onSubmitHandler\"), \" parameter.\"), mdx(\"p\", null, \"Paste this code into \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"AddEditNote.js\"), \":\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"import React, {useState, useEffect} from 'react';\\nimport RenderData from \\\"./RenderData\\\";\\nimport Form from './Form';\\n\\nconst AddEditNote = () => {\\n  const [note, setNote] = useState({});\\n\\n  useEffect( () => {\\n    const abortController = new AbortController();\\n\\n    async function fetchData() {\\n      console.log('Calling fetch...')\\n      try {\\n        const response = await fetch('http://localhost:4011/note', {\\n          signal: abortController.signal,\\n        });\\n\\n        if (response.ok) {\\n          console.log('Response received from server and is ok!')\\n          const {note} = await response.json();\\n\\n          if (abortController.signal.aborted) {\\n            console.log('Abort detected, exiting!')\\n            return;\\n          }\\n\\n          setNote(note)\\n        }\\n      } catch(e) {\\n        console.log(e)\\n      }\\n    }\\n\\n    fetchData()\\n\\n    return () => {\\n      console.log('Aborting GET request.')\\n      abortController.abort();\\n    }\\n  }, [])\\n\\n  return (\\n    <div>\\n      <RenderData\\n        data={note}\\n      />\\n      <Form\\n        entity={note}\\n        onSubmitHandler={async newNote => {\\n          const response = await fetch('http://localhost:4011/note', {\\n            method: 'POST',\\n            body: JSON.stringify(newNote),\\n            headers: {\\n              'Content-Type': 'application/json'\\n            }\\n          });\\n\\n          if (response.ok) {\\n            const res = await response.json()\\n            console.log(res)\\n          }\\n        }}\\n      />\\n    </div>\\n  );\\n};\\n\\nexport default AddEditNote\\n\")), mdx(\"p\", null, \"If you run this code, navigate to the form, edit the values then click \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"submit\"), \" and take a look at the server console, you should see the values you typed into the form have been posted back to the server and extracted from the HTTP message.\"), mdx(\"p\", null, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/simply-learn-full-stack-7\"\n  }), \"Next the Database\"), \", ...\"), mdx(\"p\", null, \"Code repo: \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/neohed/node-react-stack\"\n  }), \"Github Repository\")));\n}\n;\nMDXContent.isMDXComponent = true;"}},"pageContext":{"id":"b005ef5d-4ace-5222-b023-d44db83deae2","prev":{"id":"eb63bf5d-0384-5318-b1e3-189ac98bb7a8","parent":{"name":"index","sourceInstanceName":"blog"},"excerpt":"Simply Learn Full-Stack React & Node.js Let's jump right in! All the edits we need to make are on the server. We're gonna use Prisma ORM and SqlLite DB for convenience.  We need to install these in  node-server Install the Prisma client which express…","fields":{"title":"simply learn-full-stack-7","description":"Full-stack Adding a Database using Prisma to a Node.js app","slug":"simply-learn-full-stack-7","absolutePath":"D:/Workspace/Github/neohed-blog/content/blog/learn-full-stack-simply-07/index.mdx","banner":null,"date":"2022-11-21T11:23:41"}},"next":{"id":"926132dd-bb88-57a0-bc31-4b9579c53a0d","parent":{"name":"index","sourceInstanceName":"blog"},"excerpt":"Simply Learn Full-Stack React & Node.js Add a form to the React client site We're going to add a few components here to generate our form from our data.  There are much better libraries to do this, which we will look at later, but for now we will…","fields":{"title":"Simply Learn Full-Stack Web, Part 2","description":"Tutorial to learn full-stack with React node.js and Prisma DB","slug":"simply-learn-full-stack-2","absolutePath":"D:/Workspace/Github/neohed-blog/content/blog/learn-full-stack-simply-02/index.mdx","banner":null,"date":"2022-06-27T08:36:32"}}}}}